package com.fla.puzzle.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import android.content.Context;
import android.util.Log;

/**
 * Contains useful methods to simplify serialization\deserializtion of objects
 */
public class SerializationUtils {
    private static final String LOG_TAG = SerializationUtils.class.getName();

    public static void saveObjectToFile(Context context, String fileName, Serializable object) {
        FileOutputStream outputStream = null;
        ObjectOutputStream out = null;
        try {
            outputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);
            out = new ObjectOutputStream(outputStream);
            out.writeObject(object);
            out.close();
        }
        catch (Exception e) {
            Log.e(LOG_TAG, "Error saving object to file " + fileName, e);
        }
        finally {
            try {
                outputStream.close();
            }
            catch (IOException e) {
                Log.e(LOG_TAG, "Cannot close output stream", e);
            }
        }
    }

    public static Object restoreObjectFromFile(Context context, String fileName) {
        if (!isDataFileExist(context, fileName)) {
            return null;
        }
        FileInputStream inputStream = null;
        ObjectInputStream in = null;
        Object result = null;
        try {
            inputStream = context.openFileInput(fileName);
            in = new ObjectInputStream(inputStream);
            result = in.readObject();
            in.close();
        }
        catch (Exception e) {
            Log.e(LOG_TAG, "Error restoring object from file " + fileName, e);
        }
        finally {
            try {
                inputStream.close();
            }
            catch (IOException e) {
                Log.e(LOG_TAG, "Cannot close input stream", e);
            }
        }
        return result;
    }

    /**
     * Serializes the given object to string using Base64 algorithm
     * 
     * @param object Object object to serialize
     * @return String string representation of serialized object
     * @throws IOException if something went wrong during serialization
     */
    public static String serializeToString(Object object) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        baos.close();
        oos.close();
        return Base64.encode(baos.toByteArray());
    }
    
    /**
     * Deserializes the given object from string using Base64 algorithm
     * 
     * @param string String string representation of serialized object
     * @return Object deserialized object
     * @throws IOException if something went wrong during deserialization
     * @throws ClassNotFoundException if something went wrong during deserialization
     */
    public static Object deserializeFromString(String string) throws IOException, ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(string));
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object result = ois.readObject();
        bais.close();
        ois.close();
        return result;
    }

    private static boolean isDataFileExist(Context context, String fileName) {
        String absolutePath = context.getFilesDir() + File.separator + fileName;
        return new File(absolutePath).canRead();
    }
}
